from rest_framework import status, serializers
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.views import APIView
from rest_framework.generics import CreateAPIView

from .serializers import UserRegistrationModelSerializer, CustomTokenObtainPairSerializer
from .models import User

# 容连云
import random
from django_redis import get_redis_connection
from django.conf import settings

from .tasks import send_sms


class CustomTokenObtainPairView(TokenObtainPairView):
    """
    登陆视图
        （1）账号密码登录：
            调用序列化器验证字段，在序列化器中增加自定义载荷信息
        （2） 手机号验证码登录：
            没遵循Django REST Framework 习惯，没用序列化器，所有验证都是自己实现的，写了个函数增加自定义载荷信息
            不会进行字段验证！！！
    """
    serializer_class = CustomTokenObtainPairSerializer

    def post(self, request, *args, **kwargs):
        # 判断登录方式
        if 'sms_code' in request.data:
            # 手机号验证码登录
            return self.handle_mobile_login(request)
        else:
            # 账号密码登录
            return super().post(request, *args, **kwargs)

    def handle_mobile_login(self, request):
        # 从请求中获取手机号和验证码
        mobile = request.data.get("mobile")
        code = request.data.get("sms_code")

        # 从 Redis 获取存储的验证码
        redis_conn = get_redis_connection("sms_code")
        stored_code = redis_conn.get(f"sms_{mobile}")

        # 验证验证码是否正确
        if stored_code is None or stored_code.decode() != code:
            raise serializers.ValidationError(detail="验证码不正确或已过期", code="sms_code")

        try:
            # 根据手机号查询用户
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            raise serializers.ValidationError(detail="手机号未注册")

        # 如果手机号和验证码验证通过，生成 JWT Token
        refresh = RefreshToken.for_user(user)  # 生成 refresh token

        # 添加自定义载荷内容
        custom_claims = self.get_custom_claims(user)
        for key, value in custom_claims.items():
            refresh[key] = value

        # 返回 token 数据
        return Response({
            'refresh': str(refresh),
            'access': str(refresh.access_token),
        }, status=status.HTTP_200_OK)

    def get_custom_claims(self, user):
        """添加自定义载荷"""
        claims = {}
        if hasattr(user, 'avatar'):
            claims['avatar'] = user.avatar.url if user.avatar else ""
        if hasattr(user, 'nickname'):
            claims['nickname'] = user.nickname
        if hasattr(user, 'money'):
            claims['money'] = float(user.money)
        if hasattr(user, 'credit'):
            claims['credit'] = user.credit
        return claims


class MobileAPIView(APIView):
    def get(self, request, mobile):
        """
        校验手机号是否已注册
        :param request:
        :param mobile: 手机号
        :return:
        """
        exist = User.objects.filter(mobile=mobile).exists()
        if exist:
            return Response({"message": "当前手机号已注册"}, status=status.HTTP_400_BAD_REQUEST)
        else:
            # 如果查不到该手机号的注册记录，则证明手机号可以注册使用
            return Response({"message": "OK"}, status=status.HTTP_200_OK)


class UserRegistrationView(CreateAPIView):
    """用户注册视图"""
    queryset = User.objects.all()
    serializer_class = UserRegistrationModelSerializer


class SMSAPIView(APIView):
    """
    SMS短信接口视图
    """

    def get(self, request, mobile):
        """发送短信验证码"""
        redis = get_redis_connection("sms_code")
        # 判断手机短信是否处于发送冷却中[60秒只能发送一条]
        interval = redis.ttl(f"interval_{mobile}")  # 通过ttl方法可以获取保存在redis中的变量的剩余有效期
        if interval != -2:
            return Response(
                {"errmsg": f"短信发送过于频繁，请{interval}秒后再次点击获取!"},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 基于随机数生成短信验证码
        # code = "%06d" % random.randint(0, 999999)
        code = f"{random.randint(0, 9999):04d}"

        # 获取短信有效期的时间
        time = settings.RONGLIANYUN.get("sms_expire")

        # 短信发送间隔时间
        sms_interval = settings.RONGLIANYUN["sms_interval"]

        # 调用第三方sdk发送短信
        # send_sms(settings.RONGLIANYUN.get("reg_tid"), mobile, datas=(code, time // 60))
        # 异步发送短信
        send_sms.delay(settings.RONGLIANYUN.get("reg_tid"), mobile, datas=(code, time // 60))
        # print(settings.RONGLIANYUN.get("reg_tid"), mobile, code, time // 60)

        # 记录code到redis中，并以time作为有效期
        # 使用redis提供的管道对象pipeline来优化redis的写入操作[添加/修改/删除]
        pipe = redis.pipeline()
        pipe.multi()  # 开启事务
        pipe.setex(f"sms_{mobile}", time, code)
        pipe.setex(f"interval_{mobile}", sms_interval, "_")
        pipe.execute()  # 提交事务，同时把暂存在pipeline的数据一次性提交给redis

        return Response({"errmsg": "OK"}, status=status.HTTP_200_OK)
